package com.pig4cloud.pig.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bblocks.area.AreaVo;
import com.bblocks.common.data.handle.AreaCrawlingHandle;
import com.bblocks.dbmonitor.annotation.MonitorTable;
import com.bblocks.util.R;
import com.google.common.collect.Lists;
import com.pig4cloud.pig.admin.api.entity.SysArea;
import com.pig4cloud.pig.admin.api.entity.SysAuditLog;
import com.pig4cloud.pig.admin.mapper.SysAreaMapper;
import com.pig4cloud.pig.admin.mapper.SysAuditLogMapper;
import com.pig4cloud.pig.admin.service.SysAreaService;
import com.pig4cloud.pig.admin.service.SysAuditLogService;
import com.pig4cloud.pig.common.core.constant.CacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>Project: bblocks-pro - SysAreaServiceImpl</p>
 * <p>描述：</p>
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/3/19 16:32
 * @Version 1.0
 * @since 8
 */
@Slf4j
@MonitorTable(value="sys_area",id="id",cacheKeySpels={"#id","#parentCode","'getByParentCode&parentCode='+#parentCode","'getByLv&lv='+#lv"})
@CacheConfig(cacheNames= CacheConstants.SYS_AREA)
@Service
public class SysAreaServiceImpl extends ServiceImpl<SysAreaMapper, SysArea> implements SysAreaService {

    @Resource
    private AreaCrawlingHandle areaCrawlingHandle;

    @Cacheable(key = "'getByParentCode&parentCode='+#parentCode")
    @Override
    public List<SysArea> getByParentCode(String parentCode) {;
        return this.baseMapper
                .selectList(Wrappers.lambdaQuery(SysArea.class).eq(SysArea::getParentCode, parentCode)
                        .orderByAsc(SysArea::getPinyinPrefix)
                );
    }

    @Cacheable(key = "#code")
    @Override
    public SysArea getByCode(String code) {
        return this.baseMapper.selectOne(Wrappers.lambdaQuery(SysArea.class).eq(SysArea::getCode, code));
    }

    @Cacheable(key = "#id")
    @Override
    public SysArea get(Long id) {
        return this.baseMapper.selectById(id);
    }

    @Cacheable(key = "'getByLv&lv='+#lv")
    @Override
    public List<SysArea> getByLv(int lv) {
        return this.baseMapper
                .selectList(Wrappers.lambdaQuery(SysArea.class).eq(SysArea::getLv, lv)
                        .orderByAsc(SysArea::getPinyinPrefix)
                );
    }

    /**
     * 同步数据(目前只单服务器同步)
     */
    public synchronized void initAllByNet(int maxLv){
        String batchNo = String.valueOf(System.currentTimeMillis());

        R<List<AreaVo>> provinceRet = areaCrawlingHandle.crawlingAll(0);
        log.info("采集省份结果：{}-{}", provinceRet.getCode(),provinceRet.getData().size());

        if(provinceRet.getSucFlag()){
            updateGroupAreas(provinceRet.getData(),batchNo,true);

            provinceRet.getData().parallelStream()
                    .forEach(p->{
                log.info("开始收集省下属：{}",p.getName());
                R<List<AreaVo>> resultRet = areaCrawlingHandle.crawlingArea(p.getChildUrl(),maxLv);

                log.info("完成收集省下属：{},结果：{}-{}",p.getName(),resultRet.getCode(),resultRet.getData().size());
                List<AreaVo> all = resultRet.getData();


                //下属-城市
                List<AreaVo> proCityVos = all.stream()
                                            .filter(o->o.getParentCode().equals(p.getCode()))
                                            .collect(Collectors.toList());
                updateGroupAreas(proCityVos,batchNo,resultRet.getSucFlag());

                //城市下属区县
                groupsTrade(proCityVos,all,batchNo,resultRet.getSucFlag());
            });

        }
    }

    /**
     *
     * @param parents 城市们（2:市city,3:区县district,4:乡镇/街道street）
     * @param all
     * @param batchNo
     * @param isAll
     */
    private void groupsTrade(List<AreaVo> parents,List<AreaVo> all,String batchNo,boolean isAll){
        parents.forEach(vo->{
            //下属-
            List<AreaVo> childVos = all.stream()
                    .filter(o->o.getParentCode().equals(vo.getCode()))
                    .collect(Collectors.toList());

            if(childVos.isEmpty())//未采集、或者未采集到
                return;

            log.info("收集下属：{}-{}-{}-{}",vo.getName(),vo.getCode(),vo.getChildUrl(),childVos.size());
            updateGroupAreas(childVos,batchNo,isAll);

           //2-4可以下钻
            if(vo.getLv() <= 4){
                groupsTrade(childVos,all,batchNo,isAll);
            }
        });
    }


    /**
     * 更新一组数据
     * 1、单纯只是，新增or更新
     * 2、如果是完整，则本组非本批次的废弃
     * @param areaVos 一组数据
     * @param isAll 是否全部-采集成功即为全部
     */
    private void updateGroupAreas(List<AreaVo> areaVos,String batchNo,boolean isAll){
        int lv = areaVos.get(0).getLv();
        String parentCode = areaVos.get(0).getParentCode();
        List<SysArea> groupAreas = null;
        if(lv == 1){
            groupAreas =  getByLv( 1 );
        }else{
            groupAreas =  getByParentCode(parentCode);
        }

        //单纯只是，新增or更新
        List<SysArea> groupAreasFinal = groupAreas;
        List<String> noChangeExtCodes = Lists.newArrayList();
        List<SysArea> toSaveAreas = Lists.newArrayList();
        areaVos.forEach(pvo->{
                Optional<SysArea> exist = groupAreasFinal
                        .stream()
                        .filter(p->p.getExtCode().equals(pvo.getCode()))
                        .findAny();
                if(exist.isPresent()){//更新
                   int isUpdate = updateIfDiff(exist.get(),pvo,batchNo);
                   if(isUpdate == 0){
                       noChangeExtCodes.add(pvo.getCode());
                   }
                }else{//新增
                    toSaveAreas.add(this.save(pvo,batchNo));
                }
        });

        //批量保存
        if(CollUtil.isNotEmpty(toSaveAreas)){
            this.saveBatch(toSaveAreas);
        }

        //批量修改为时间和批次
        if(CollUtil.isNotEmpty(noChangeExtCodes)){
            this.baseMapper.update(SysArea.builder()
                    .batchNo(batchNo)
                    .updateTime(LocalDateTime.now())
                    .build(), Wrappers.lambdaQuery(SysArea.class).in(SysArea::getExtCode,noChangeExtCodes));
        }

        //如果本次集采完整，其他的标记为废弃（非本批次，非本组）
        if(isAll){
           int delNum = this.baseMapper
                    .delete(Wrappers.lambdaQuery(SysArea.class)
                    .eq(lv == 1,SysArea::getLv,lv)
                    .eq(lv!=1,SysArea::getParentCode,parentCode)

                    .ne(SysArea::getBatchNo,batchNo)
                    );
           log.info("本组清除出无效数量：{}",delNum);
        }
    }


    /**
     * 保存一个(不保存-后面批量)
     * @param pvo
     * @return
     */
    private SysArea save(AreaVo pvo,String batchNo) {
        String pinyin = PinyinUtil.getPinyin(pvo.getName());
        SysArea sysArea = SysArea.builder()
                .code(pvo.getCode())
                .extCode(pvo.getCode())
                .extName(pvo.getName())
                .fullName(pvo.getName())
                .lv(pvo.getLv())
                .parentCode(pvo.getParentCode())
                .name(pvo.getName())
                .pinyin(pinyin)
                .pinyinPrefix(pinyin.substring(0,1).toUpperCase())
                .updateTime(LocalDateTime.now())
                .batchNo(batchNo)
                .build();
       // this.baseMapper.insert(sysArea);
        return sysArea;
    }

    /**
     * 如果存在不一致则更新（code是一致的）
     * @param sysArea
     * @param newAreaVo 新的数据
     * @return
     */
    private int updateIfDiff(SysArea sysArea,AreaVo newAreaVo,String batchNo) {
        boolean diff = false;
        if(!ObjectUtil.equals(sysArea.getLv(),newAreaVo.getLv()))
        {
            diff = true;
            sysArea.setLv(newAreaVo.getLv());
        }
        if(!ObjectUtil.equals(sysArea.getName(),newAreaVo.getName()))
        {
            diff = true;
            sysArea.setName(newAreaVo.getName());
            sysArea.setFullName(newAreaVo.getName());
        }

        if(!ObjectUtil.equals(sysArea.getParentCode(),newAreaVo.getParentCode())) {
            diff = true;
            sysArea.setParentCode(newAreaVo.getParentCode());
        }


        if(diff) {
            sysArea.setExtCode(newAreaVo.getCode());
            sysArea.setExtName(newAreaVo.getName());
            String pinyin = PinyinUtil.getPinyin(newAreaVo.getName());

            sysArea.setPinyin(pinyin);
            sysArea.setPinyinPrefix(pinyin.substring(0, 1).toUpperCase());

            sysArea.setUpdateTime(LocalDateTime.now());
            sysArea.setBatchNo(batchNo);
            return this.baseMapper.updateById(sysArea);
        }else{
            return 0;
        }
    }

}
